/**++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**
 *  @author     Andrew Wei
 *  @portfolio  http://andrewwei.mu
 *
 *  ©2012 Andrew Wei
 *
 *  This software is released under the MIT License:
 *  http://www.opensource.org/licenses/mit-license.php
 **++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++**/
package com.ghoztudios.display
{
    import com.ghoztudios.events.DynamicContentEvent;
    import com.ghoztudios.events.EnhancedEvent;
    import com.greensock.TweenMax;
    import com.greensock.easing.Quart;

    import flash.events.Event;
    import flash.events.MouseEvent;

    /**
     *
     * Scrolling arrow for DynamicContentDisplayObject instances.
     *
     * @langversion     3.0
     * @playerversion   Flash 10.3.183.20
     */
    public class ScrollArrow extends SwitchOnStage
    {
        private static const ID:String = 'com.ghoztudios.display.ScrollArrow';


        // Constants
        /**
         * Set of detectable directions of control.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        public static const DIRECTION_UP:String    = 'up';
        public static const DIRECTION_RIGHT:String = 'right';
        public static const DIRECTION_DOWN:String  = 'down';
        public static const DIRECTION_LEFT:String  = 'left';


        // Private Properties
        /**
         * Control direction.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _direction:String = null;

        /**
         * Target DynamicContentDisplayObject instance.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _target:DynamicContentDisplayObject = null;

        /**
         * Beginning y-coordinate of scroll.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _topY:Number = NaN;

        /**
         * Ending y-coordinate of scroll.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _bottomY:Number = NaN;

        /**
         * Beginning x-coordinate of scroll.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _leftX:Number = NaN;

        /**
         * Ending x-coordinate of scroll.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _rightX:Number = NaN;

        /**
         * Scroll tween duration.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _duration:Number = 0;

        /**
         * Scroll tween duration offset.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _durationOffset:Number = 0;

        /**
         * Scroll interval.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _scrollInterval:Number = 60;

        /**
         * Scroll speed.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _scrollSpeed:Number = 12;

        /**
         * Scroll acceleration.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _acceleration:Number = 1;

        /**
         * Scroll destination.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private var _destination:Number = NaN;


        // Setter Methods
        /**
         * Sets the scroll interval.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        public function set scrollInterval($value:Number):void { _scrollInterval = $value; }

        /**
         * Sets the scrolling speed.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        public function set scrollSpeed($value:Number):void { _scrollSpeed = $value; }


        // Initialization
        /**
         * Creates a new ScrollArrow instance.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        public function ScrollArrow():void {}


        // Protected Methods
        /**
         * Destroy function.
         *
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        override protected function _destroy():void
        {
            _target = null;

            if (hasEventListener(MouseEvent.MOUSE_DOWN)) removeEventListener(MouseEvent.MOUSE_DOWN, _onStartScroll);
            if (hasEventListener(MouseEvent.MOUSE_UP))   removeEventListener(MouseEvent.MOUSE_UP, _onStopScroll);
            if (hasEventListener(MouseEvent.MOUSE_OUT))  removeEventListener(MouseEvent.MOUSE_OUT, _onStopScroll);
        }


        // Public Methods
        /**
         * Public init function. Sets the target DynamicContentDisplayObject instance and control direction.
         *
         * @param   $target
         * @param   $direction
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        public function init($target:DynamicContentDisplayObject, $direction:String):void
        {
            _target    = $target;
            _direction = $direction;

            _target.addEventListener(Event.REMOVED_FROM_STAGE, _targetRemovedFromStageHandler);

            addEventListener(MouseEvent.MOUSE_DOWN, _onStartScroll, false, 0, true);
            addEventListener(MouseEvent.MOUSE_UP, _onStopScroll, false, 0, true);
            addEventListener(MouseEvent.MOUSE_OUT, _onStopScroll, false, 0, true);
        }


        // Event Handlers
        /**
         * flash.events.Event.REMOVED_FROM_STAGE handler for the target.
         *
         * @param   $event
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private function _targetRemovedFromStageHandler($event:Event):void
        {
            _target = null;

            if (hasEventListener(MouseEvent.MOUSE_DOWN)) removeEventListener(MouseEvent.MOUSE_DOWN, _onStartScroll);
            if (hasEventListener(MouseEvent.MOUSE_UP))   removeEventListener(MouseEvent.MOUSE_UP, _onStopScroll);
            if (hasEventListener(MouseEvent.MOUSE_OUT))  removeEventListener(MouseEvent.MOUSE_OUT, _onStopScroll);
        }

        /**
         * flash.events.MouseEvent.MOUSE_DOWN handler for start scrolling.
         *
         * @param   $event
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private function _onStartScroll($event:MouseEvent):void
        {
            _topY    = _target.fov.y;
            _leftX   = _target.fov.x;
            _bottomY = ((_target.displayHeight - _target.contentHeight) > 0) ? _topY : (_target.displayHeight - _target.contentHeight);
            _rightX  = ((_target.displayWidth - _target.contentWidth) > 0) ? _leftX : (_target.displayWidth - _target.contentWidth);

            if ((_direction == DIRECTION_UP) || (_direction == DIRECTION_DOWN))
                _destination = _target.content.y;

            if ((_direction == DIRECTION_LEFT) || (_direction == DIRECTION_RIGHT))
                _destination = _target.content.x;

            if (!hasEventListener(Event.ENTER_FRAME))
                addEventListener(Event.ENTER_FRAME, _onScroll, false, 0, true);
        }

        /**
         * MouseEvent.MOUSE_UP handler for stop scrolling.
         *
         * @param   $event
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private function _onStopScroll($event:MouseEvent):void
        {
            if (hasEventListener(Event.ENTER_FRAME)) { removeEventListener(Event.ENTER_FRAME, _onScroll); }

            _duration = 0;
            _durationOffset = 0;
        }

        /**
         * Event.ENTER_FRAME handler for scrolling.
         *
         * @param   $event
         * @langversion     3.0
         * @playerversion   Flash 10.3.183.20
         */
        private function _onScroll($event:Event):void
        {
            switch (_direction)
            {
                case DIRECTION_UP:
                    if (_duration % _scrollSpeed == 0)
                    {
                        if (_target.content.y < _topY)
                        {
                            if ((_destination + _scrollInterval) > _topY)
                            {
                                _destination = _topY;
                                dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLL_END));
                            }
                            else
                            {
                                _destination += _scrollInterval;
                                dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLLING));
                            }

                            if (_durationOffset < _scrollSpeed - 1)
                                _durationOffset += _acceleration;

                            _duration = _durationOffset;
                            TweenMax.to(_target.content, 0.5, {y:_destination, ease:Quart.easeOut});
                        }
                        else
                        {
                            TweenMax.to(_target.content, 0.5, {y:_topY, ease:Quart.easeOut});
                            dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLL_END));
                        }
                    }

                    _duration++;
                    break;
                case DIRECTION_DOWN:
                    if (_duration % _scrollSpeed == 0)
                    {
                        if (_target.content.y > _bottomY)
                        {
                            if ((_destination - _scrollInterval) < _bottomY)
                            {
                                _destination = _bottomY;
                                dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLL_END));
                            }
                            else
                            {
                                _destination -= _scrollInterval;
                                dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLLING));
                            }

                            if (_durationOffset < _scrollSpeed - 1) _durationOffset += _acceleration;
                            _duration = _durationOffset;
                            TweenMax.to(_target.content, 0.5, {y:_destination, ease:Quart.easeOut});
                        }
                        else
                        {
                            TweenMax.to(_target.content, 0.5, {y:_bottomY, ease:Quart.easeOut});
                            dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLL_END));
                        }
                    }

                    _duration++;
                    break;
                case DIRECTION_LEFT:
                    if (_duration % _scrollSpeed == 0)
                    {
                        if (_target.content.x < _leftX)
                        {
                            if ((_destination + _scrollInterval) > _leftX)
                            {
                                _destination = _leftX;
                                dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLL_END));
                            }
                            else
                            {
                                _destination += _scrollInterval;
                                dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLLING));
                            }

                            if (_durationOffset < _scrollSpeed - 1) _durationOffset += _acceleration;
                            _duration = _durationOffset;
                            TweenMax.to(_target.content, 0.5, {x:_destination, ease:Quart.easeOut});
                        }
                        else
                        {
                            TweenMax.to(_target.content, 0.5, {x:_leftX, ease:Quart.easeOut});
                            dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLL_END));
                        }
                    }

                    _duration++;
                    break;
                case DIRECTION_RIGHT:
                    if (_duration % _scrollSpeed == 0)
                    {
                        if (_target.content.x > _rightX)
                        {
                            if ((_destination - _scrollInterval) < _rightX)
                            {
                                _destination = _rightX;
                                dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLL_END));
                            }
                            else
                            {
                                _destination -= _scrollInterval;
                                dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLLING));
                            }

                            if (_durationOffset < _scrollSpeed - 1) _durationOffset += _acceleration;
                            _duration = _durationOffset;
                            TweenMax.to(_target.content, 0.5, {x:_destination, ease:Quart.easeOut});
                        }
                        else
                        {
                            TweenMax.to(_target.content, 0.5, {x:_rightX, ease:Quart.easeOut});
                            dispatchEvent(new DynamicContentEvent(DynamicContentEvent.SCROLL_END));
                        }
                    }

                    _duration++;
                    break;
            }
        }
    }
}
